[][]
[Magento 1.9 Docker from Alex Cheng][https://github.com/alexcheng1982/docker-magento] 是比较好的1.9 版本magento docker image,包含样例数据和script installation. 但是需要自己绑定volumn 去同步个别需要的文件夹。这里列出自定义docker-compose.yml
web:
image: alexcheng/magento
ports:
- "80:80"
links:
- mysql
volumes:
- /Users/ethanzhang/Desktop/MagentoDev/Magento/app:/var/www/htdocs/app
- /Users/ethanzhang/Desktop/MagentoDev/Magento/skin:/var/www/htdocs/skin
env_file:
- .env
mysql:
image: mysql:5.6.23
env_file:
- .env
如需清空所有image 和container 推倒重来,script 如下
- Flush container:
docker stop $(docker ps -a -q)docker rm $(docker ps -a -q) - image cleanup script:
docker stop $(docker ps -a -q)docker rm $(docker ps -a -q)docker rmi $(docker images -a -q)
一开始install 的时候不能有volumes,这样会让magento 误以为已经安装了。所以需要先去掉volumn,成功导入数据并安装magento,之后在加上volumn,用 docker-compose up -d 去重新加载 docker-compose.yml
新建module 流程
[这里][http://devdocs.magento.com/guides/m1x/magefordev/mage-for-dev-4.html] 有详细的Tutorial,下面笔记均出自上述文档
Initialize
我们从Package Magentotutorial作为命名空间,开始创建一个叫做Helloword 的module,结构如下
app/code/local/Magentotutorial/Helloworld/Block
app/code/local/Magentotutorial/Helloworld/controllers
app/code/local/Magentotutorial/Helloworld/etc
app/code/local/Magentotutorial/Helloworld/Helper
app/code/local/Magentotutorial/Helloworld/Model
app/code/local/Magentotutorial/Helloworld/sql
- 在
app/code/local/Magentotutorial/Helloworld/etc/config.xml中定义版本等基本信息 - 在
app/etc/modules/Magentotutorial_Helloworld.xml中定义active 激活module - 清除Magento 缓存,在
**System->Configuration->Advanced->Disable Modules Output中找到创建的module,表示module激活成功
Router
/* app/code/local/Magentotutorial/Helloworld/etc/config.xml */
<config>
...
<frontend>
<routers>
<helloworld>
<use>standard</use>
<args>
<module>Magentotutorial_Helloworld</module> // 对应module 文件名
<frontName>helloworld</frontName>
</args>
</helloworld>
</routers>
</frontend>
...
</config>
Magento 解析URL:http://example.com/frontName/actionControllerName/actionMethod/
上述URL解析为:http://example.com/helloworld/*
添加Action Controller
app/code/local/Magentotutorial/Helloworld/controllers/IndexController.php写入方法
indexAction<?php class Magentotutorial_Helloworld_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { echo 'Hello World'; } }清理缓存,就可以在
http://example.com/helloworld/index/index看到输出的Helloworld可以看到,因为
actionControllerName是IndexController.php;actionMethod是indexAction,所以URL为/index/index如果有个方法叫做
goodjobAction,那么URL就是http://example.com/helloworld/index/goodjob如果新增一个
MessageController.php和一个方法helloAction,那么就可以访问http://local.magento/helloworld/message/hello因为继承了front action 类,可以用一些方法,如
public function paramsAction() { foreach($this->getRequest()->getParams() as $key=>$value) { echo 'Param: '.$key.''; echo 'Value: '.$value.''; echo '</br>'; } }可以看到传递的参数和值,参见
http://local.magento/helloworld/index/params?foo=bar&baz=eof
Layout, Block & Template
Magento 和其他PHP MVC 不同,它的数据并不从Controller 传给 View,而是通过View直接去获取系统数据。
因此,View 被分成了Block 和Template两部分,Block 是PHP Object 提供方法和数据,Template 是PHTML 格式下的混写。每一个Block 只针对一个Template。在PHTML 中,$this 直接指向对应的Block Object。
如Template app/design/frontend/base/default/template/catalog/product/list.phtml
那么它对应的Block Object 在 app/code/core/Mage/Catalog/Block/Product/List.php
可见从 Catelog->Product->List 都是以一一对应的
- xml文件全部在:
app\design\frontend\base\default\layout,控制布局 - phtml文件以及文件夹全部在在:
app\design\frontend\base\default\template,控制模版
Template: PHTML
通过PHP 在HTML 中进行数据加载和渲染
<?php $_productCollection=$this->getLoadedProductCollection() ?>
<?php if(!$_productCollection->count()): ?> <div class="note-msg">
<?php echo $this->__("There are no products matching the selection.") ?>
</div> <?php else: ?>
实际流程
<-->create app/design/frontend/base/default/layout/local.xml</->
<layout version="0.1.0">
<default>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" />
</default>
</layout>
/* create app/design/frontend/base/default/template/magentotutorial/helloworld/simple_page.phtml */
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Hello World</title>
<style type="text/css">
h1 {color:#f00;}
</style>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
/* edit app/code/local/Magentotutorial/Helloworld/controllers/IndexController.php */
public function indexAction() {
//remove our previous echo
//echo 'Hello Index!';
$this->loadLayout();
$this->renderLayout();
}
这时打开 http://local.magento/helloworld/index/index 我们能看到红色的Hello World,事实上实际流程如下:
在Controller 里面调用
$this->loadLayout();会进行如下操作:- Magento 会自定义的许多block,action等等,会先根据这些信息生成一个
Layout XML - 整理
Layout XML中所有的block 并存在全局变量_block数组中 - 将所有有
output属性的block 存在全局变量_output中
- Magento 会自定义的许多block,action等等,会先根据这些信息生成一个
在Controller 里面调用
$this->renderLayout();会遍历_output中的所有Block ,并将output 属性的值用来进行回调。当值为toHtml时,表示输出到Template 属性指向的template我们在
local.xml里定义的<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" />实际上override 了同为page/html类型,名为root 的一个block,把它的内容指向了我们新建的phtml模版Layout XML还包含reference tag<reference name="" />,这代表reference 里面的block 会被hook到相应的name指代的block 中去Handles
生成
Layout XML的依据,可以通过[LayoutViewer][http://alanstorm.com/2005/projects/MagentoLayoutViewer.tar.gz] 插件查看,如上述地址包含了五个handles:defaultSTORE_bare_usTHEME_frontend_default_defaulthelloworld_index_indexcustomer_logged_out
其中
default每个页面都有,而helloworld_index_inde则因为我们的route 指向了helloworld/index/index现在所有页面都是Helloword,因为我们override 了
default root handles,而它会作用于所有页面。// local.xml before <layout version="0.1.0"> <default> <block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" /> </default> </layout> // local.xml now <layout version="0.1.0"> <helloworld_index_index> <block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" /> </helloworld_index_index> </layout>我们发现,现在的页面不是作用于
default root handles,而是helloworld root handles,这意味着只有我们的helloworld 页面才会收到影响。
Nesting Blocks
Block&Template 模式,是通过一层一层block 互相嵌套而成的。
最顶层Block 通常位于app/design/frontend/base/default/template/page/one-column.phtml
然后通过<?php echo $this->getChildHtml('head') ?> getChildHtml 方法加载head,content,body 等等
在我们的例子里,也可以嵌套其他block。首先要在local.xml 里声明,其次在phtml里使用
<helloworld_index_index>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml">
<block type="page/template_links" name="top.links"/>
<block type="customer/form_register" name="customer_form_register" template="customer/form/register.phtml"/>
</block>
</helloworld_index_index>
<body>
<?php echo $this->getChildHtml('top.links'); ?>
<h1>Hello World</h1>
<?php echo $this->getChildHtml('customer_form_register'); ?>
</body>
首先在我们的root block 里声明嵌套top.links 和 customer_form_register,之后就可以在phtml 中通过 $this->getChildHtml(name) 的方式进行使用
Action
acution其实就是调用一个方法,例如常用的setTemplate,指定需要的模版
<helloworld_index_index>
<reference name="root">
<action method="setTemplate">
<template>magentotutorial/helloworld/simple_page.phtml</template>
</action>
<block type="page/template_links" name="top.links"/>
<block type="customer/form_register" name="customer_form_register" template="customer/form/register.phtml"/>
</reference>
</helloworld_index_index>
这样的方式和之前的有一样的效果,只是我们不再显式的把回调页面写在block 中,而是用一个action 去完成这个动作。
Designer
[这里][http://info2.magento.com/rs/magentosoftware/images/MagentoDesignGuide.pdf] 是1.9版本的design 文档
Package & Theme
Design Package 公司名,必须有一个,默认为default 或者base package,可以包含多个Theme
Theme 实际控制theme 的东西,有两部分组成:
Template Info: Layout Xml, Template PHTML, Theme Translation Files
app/design/frontend/Ethan/default/layout/templatelocaleSkin Info: CSS, Image, and Theme Specific JS files
skin/frontend/Ethan/defaul每个design package 必须至少包含一个 default theme, 如果设定的时候只指定了package而没有theme,那么默认会读取default theme。
default theme 必须包含全部需要的文件,但是其他的Theme 就不需要,可多可少,缺了的就从default 里面拿,只override 需要的内容,所以这些theme 也被称为 “Theme Variation”

Apply Theme
在控制面板进入 System -> Configuration -> Design tab
- 点开package,手动输入 current package name (ethan),如果留空,默认base
- 点开theme,手动输入想要的theme,如果留空,默认default
- 保存即可
- 切记注意左上角的“Current Configration Scope”, 可以为不同的website 选择不同样式,如果发现修改theme 不起作用,可以看看是否没有选对scope
如果需要对个别设备做responsive web design,那么Magento 提供了一个 Design Exception 实现
在apply theme 的页面中,可以看到针对Translation, Template, Skin, Layout 和 Default 的专属设置
在这里我们可以针对不同设备进行相应的match,如下图所示

Theme Fallback Model
Fallback Model 其实很好理解,就是说如果找不到某个文件,就逐级向上去寻找,直到找到为止。这个 “上” 表示从 Ethan/niceTheme -> Ethan/defaultTheme -> Base/defaultTheme 这种逐级关系。因为Theme Variation 不需要所有必要文件,Deafult Theme 要求有所有必要文件但是不必须, Base / Default Them 是安装时自带的 final fallback point,最基本但不代表文件最全,很多skin asset 都没有,如果还找不到,那么报错。如下图所示。

Fallback Model 的优点在于可以维护尽量少的代码,而且便于更新。只要更新了base 的样式,会应用到所有没有特别override 的元素上。
Block & Layout
Structural Block
结构性block,如Header, Left Column, Main Column 和 Footer 等
Content Block
在Structural Block 中具体安放内容的Block,如Catogory List, Mini Cart, Product Listing 等等
Layout
链接结构性Block 和 Content Block 的文件
It defines both the structural and content blocks and then inform Magento how and where to connect them up.

Widget
有预设选项的前端Block 集合,可以通过控制面板进行增减、配置。便于非编程人员快速添加内容。例如:CMS Page Link,最近浏览过的内容,投票、标签、分组栏甚至Flash 动画等等。
创建Theme
新建一个属于自己的Theme流程及注意事项如下
构建骨架
- 新建
app/design/frontend/Ethan/default/layout/templatelocale - 新建
skin/frontend/Ethan/defaultimagescssjs - 再次强调,在自己customlize theme 的时候,切起不要 ”build from scratch“ 而是要在default theme 甚至base package 的基础上新添自己的内容和样式。
- 在编辑CSS 文件时,不要使用CSS Visiability 去隐藏或显示Block,而只应该用于具体内容上。
- 控制面板 Design Tab 上还有一些关于header,footer,水印等设置。
Style
所有的Style 都通过CSS 和相关的Images 文件控制,如果不确定在哪里,可以先复制主要的style.css 再逐级修改增减。
Layout
所有的布局 (HTML) 都通过Magento Layout & Block 控制。
Layout 是把Content Block 分配到Structural Block 里去的XML文件,Structural Block 和 Content Block 的区别见下图

Structural Content 的默认layout 配置位于 app/design/frontend/base/default/layout/page.xml
默认的Page Template 位于 app/design/frontend/base/default/template/page/
默认的基本Layout 配置位于 app/design/frontend/base/default/layout 或者 customer.xml 等都是用来连接与之对应的module 用的。
Layout 可以无缝的管理各种Block,从而极大的方便了我们管理Block (功能)。如果想要添加、删除Block,只需要在Layout 文件里声明Block 即可。

Handles
Handle 是Layout XML 中一个一个的XML Tag,每个Layout XML 都包含一个default handle,表示这个Layout 里一定会更新的内容。此外,还可以有多个其他handler,在不同的页面上触发。
上图是layout/page.xml 截图,default 的内容在每个页面都会有,但是其他的handle 如print,page_empty 等等都是特定情况下才会触发。
Blocks
Structural Block 和 Content Block 一般可以用 as 属性区分。一般来说,structural block 代表了header, content, footer 等等,这些信息都在as 属性中,如 <block type="page/html_head" name="head" as="head">。Block 一般有下面几个属性:
- Type:define the functionality of the block
- Name:可以在reference tag 如
<reference name="root">中被引用的名字 - Before / After:
before=“-” and after=“-”用来确定block 在结构blcok 中的位置 - Template:可选,如果有就包含进指代的PHTML 文件
- Action:功能性tag,如引入javscript、引入HTML等
- As:可以在PHP 方法
getChildHtml(‘block_name’)中被引用的名字
Reference
reference tag 用来引用其他block,并将reference 中更新的内容更新到引用的block中去,例子如下
<default>
<block type="page/html" name="root" output="toHtml" template="page/3columns.phtml">
...
</block>
</default>
...
<page_empty translate="label">
<label>All Empty Layout Pages</label>
<reference name="root">
<action method="setTemplate"><template>page/empty.phtml</template></action>
<!-- Mark root page block that template is applied -->
<action method="setIsHandle"><applied>1</applied></action>
<action method="setLayoutCode"><name>empty</name></action>
</reference>
</page_empty>
上例中,root 是default handle 下的主block,但是一旦触发了 page_empty 的条件,就会把reference 中的内容添加到Block root 中并执行。
Locate Layout File
如何找到页面对应的LayoutFile 很困难,所以需要开启Template Hint 功能。
admin panel -> System -> Config -> Advanced -> Developer -> Debug -> enable Tamplate path hint
如果找不到hint 选项,要换到除default config 以外其他的config scope 去。
例如,一个mini cart 的hint 为:frontend/ethan/default/template/checkout/cart/minicart.phtml
就有两个重要信息:
- 这个mini cart 属于checkout module,那么就应该去
checkout.xml中找layout 对应关系,看是否需要删减 - 这个mini cart 的 phtml 位置,可以改变组建具体内部构成